<template>
  <div
    :id="selectId"
    v-loading="isVisualVappShowLoadingProgress && isLoading"
    class="select-box"
    :class="`${componentStyle} ${componentStyle}-Style`"
    :style="boxStyle"
  >
    <AdvancedLinkageToolbar :wid="widgetInstanceId" :config="config" />
    <div v-if="!isDataAbnormal" :class="['select-content', `${isTitleSignVisiable ? 'relativePos' : ''}`]">
      <span v-if="config.config.property.istitleMarker" class="mapping-scope">*</span>
      <span
        v-if="config.config.property.isTitleSignVisiable"
        class="sign"
        :style="
          getCssStyle({
            marginLeft: config.config.property.signMarginLeft,
            backgroundColor: config.config.property.verticalLineBackgroundColor,
          })
        "
      ></span>
      <span
        v-show="title"
        id="select-title"
        class="select-title"
        :style="{
          ...getCssStyle('title', { fontSize: 12 }),
          ...getCssStyle('titleSize'),
        }"
      >{{ title }}</span>
      <el-select
        v-if="!isLoading && !grouped"
        :id="`defSelect${widgetInstanceId}`"
        ref="defSelect"
        v-model="selectVal"
        :popper-append-to-body="true"
        :class="`select-box-select select-box-select-${componentStyle}`"
        :popper-class="
          [
            `select-component-popper-${componentStyle}`,
            `select-poper1-${componentStyle}`,
            `select-scrollbar-wrap`,
            `extStyle_${widgetInstanceId}`,
            `${componentStyle}-Style`,
          ].join(' ')
        "
        clearable
        filterable
        :multiple="multiple"
        :multiple-limit="multiMaxCount"
        :collapse-tags="true"
        size="default"
        :placeholder="$demoi18n('view.select.placeholder')"
        :no-data-text="$demoi18n('message.noData')"
        @change="optionChanged(true)"
      >
        <el-option
          v-for="(item, index) in selectContentOptions"
          :key="index"
          :class="
            `select-box-select-option select-box-select-option-${componentStyle} select-box-select-option-${widgetInstanceId}`
          "
          :label="item.name"
          :value="item.key"
        ></el-option>
      </el-select>
      <div v-if="!isLoading && grouped" class="regions-tree-body">
        <div style="position: relative;">
          <el-input
            v-model="filterText"
            :placeholder="$demoi18n('word.plsInput')"
            class="regions-tree-search"
            clearable
            @clear="regionsClick(filterText)"
            @focus="filterTreeFun('')"
            @keyup.enter="filterTreeFun(filterText)"
          ></el-input>
        </div>
        <el-tree
          v-show="filterTreeShow"
          ref="tree"
          class="filter-tree"
          node-key="id"
          :data="groupOptions"
          :props="defaultProps"
          default-expand-all
          highlight-current
          :filter-node-method="filterNode"
          @node-click="regionsClick"
        >
        </el-tree>
      </div>
    </div>
    <AbnormalData :isDataAbnormal="isDataAbnormal" :boxBgColor="boxBgColor" :abnormalType="abnormalType" />
  </div>
</template>
<script>
import AdvancedLinkageToolbar from '@/components/common/advanced-linkage/advanced-linkage-toolbar.vue';
import EventBus from '@/event-bus/EventBus.js';
import chartBase from '@/mixin/chart-base.js';
import emitComponentBase from '@/mixin/emit-component-base.js';
import filterComponentMixin from '@/mixin/filter-component-mixin.js';
import dataModel from '@/models/panel-config-data.js';
import { EMIT_PARAMS_OBJ } from '@/utils/constant';
import { debounce, isEmpty, mergeObj, objHas, setBoxBackground, visualAction, getVmPageStatus } from '@/utils/util';
import { nextTick } from 'vue';
import { mapMutations } from 'vuex';
import AbnormalData from '../common/abnormal-data/abnormal-data.vue';
import config from './config/config';
import { getMatchUrlEvents } from '@/mixin/url-params/url-params-util.js';

export default {
  name: 'VisualComponentsSelect',
  components: { AbnormalData, AdvancedLinkageToolbar },
  mixins: [chartBase, emitComponentBase, filterComponentMixin],
  props: ['pareentId', 'widgetId', 'widgetInstanceId', 'isDesignView', 'widgetName', 'identifier', 'layout', 'w', 'h'],
  data() {
    let _config = this.config || config;
    _config = JSON.parse(JSON.stringify(_config));
    const { data } = _config.config;
    let { property } = _config.config;

    // 合并config.js属性，防止新增属性缺失而报错
    const _property = JSON.parse(JSON.stringify(config.config.property));
    property = mergeObj(_property, property);

    return {
      xvueTheme: window._adoPremise.uc.theme,
      orgConfig: null,
      selectId: 'select',
      title: '',
      selectVal: null,
      selectContentOptions: [],
      hasDefaultVal: data.hasDefaultVal,
      defaultVal: data.defaultValEvent ? '' : data.defaultVal || '',
      defaultValFrom: data.defaultValFrom || 'first',

      componentStyleClass: {
        light: true,
        dark: false,
      },
      selectStyle: {
        width: '',
      },

      boxStyle: {
        backgroundColor: '',
      },
      isLoading: false,
      clearable: true, // 自定义可以清空，动态数据不可以清空(why?)
      ignoreBaseEmitComponentStatus: true, // 忽略base文件中watch的emitComponentStatus
      historyOpen: true,
      hasPageWidgetsMounted: false, // 组件是否加载完成
      filterText: '',
      defaultProps: {
        children: 'children',
        label: 'label',
      },
      filterTreeShow: false,
      defaultValEventObj: null,
      ...property,
    };
  },
  computed: {
    grouped() {
      // 是否做分组
      const hasLabel = this.selectContentOptions.some(n => n.label);
      return hasLabel;
    },
    groupOptions() {
      if (!this.grouped) {
        return [];
      }
      const obj = {};
      this.selectContentOptions.forEach((n, index) => {
        if (!obj[n.label]) {
          obj[n.label] = {
            id: index,
            label: n.label,
            children: [],
          };
        }
        obj[n.label].children.push({ id: index, label: n.name, key: n.key });
      });
      const arr = Object.values(obj);
      return arr;
    },
  },
  watch: {

    // 发出组件状态，是否已经全部就绪
    emitComponentStatus(newVal) {
      if (this.hasWatchEmitComponentStatusTrue) {
        return;
      }
      if (newVal && this.pageStatus) {
        this.hasWatchEmitComponentStatusTrue = true;
        clearTimeout(this.historyTimer);
        this.historyTimer = setTimeout(() => {
          this.clearCompHistory(); // 清空历史记录，防止其他联动触发类型组件时还是取历史记录
        }, window.historyKeepTime || 10000);
      }
    },
    selectContentOptions() {
      this.selectContentOptionsChanged();
    },

    selectVal(newVal, oldVal) {
      if (isEmpty(newVal) && isEmpty(oldVal)) {
        return;
      }
      this._setComponentStatus(false);
      this.componentStatusReadyRun(() => {
        this.emitQuery();
      }, 50);
    },

    filterText(val) {
      this.$refs.tree && this.$refs.tree.filter(val);
    },

    multiple() {
      this.isLoading = true;
      nextTick(() => {
        this.isLoading = false;
      });
    },
    isLoading(newVal, oldVal) {
      if (oldVal === true) {
        nextTick(() => {
          this.setBorderRadius();
        });
      }
    },
    filterTreeShow(isShow) {
      const xvueGrid = document.querySelector('.widget-desinger');
      if (isShow) {
        document.addEventListener('click', this.hideTree);
        if (xvueGrid) {
          xvueGrid.addEventListener('click', this.hideTree);
        }
      } else {
        document.removeEventListener('click', this.hideTree);
        if (xvueGrid) {
          xvueGrid.removeEventListener('click', this.hideTree);
        }
      }
    },

    // 默认值事件监控
    'advancedLinkage.linkageDatas'() {
      const dfValEvents = this.getAdvDfValEvents();
      const ev = dfValEvents.pop();
      if (ev) {
        ev.params.forEach(n => {
          this.defaultValEventObj = {
            eventKey: ev.evtKey,
            wid: n.wid,
            evtParameterKey: n.evtParameterKey,
            evtParameterVal: n.evtParameterVal,
          };
        });
      }
    },
  },
  created() {
    this.selectId = `${this.selectId}_${this.widgetInstanceId}`;
    this.orgConfig = config;
    this.config = JSON.parse(JSON.stringify(this.orgConfig));
    this._setComponentStatus(true);
    this._getSelectContentOptions = debounce(this.getSelectContentOptions, 200);
    this.debounceGetData = this._getSelectContentOptions; // 高级事件联动需要这个方法
  },
  mounted() {
    EventBus.$once('page-widgets-mounted', () => {
      this.hasPageWidgetsMounted = true;

      // 如果此时已获取到下拉内容，则触发
      if (!this.isDesignView && this.selectContentOptions.length) {
        this.selectContentOptionsChanged();
      }
    });
  },
  beforeUnmount() {
    this.saveCompHistory(['selectVal']);
  },
  unmounted() {
    EventBus.$off('page-widgets-mounted');
  },
  methods: {
    hideTree(e) {
      const el = e.target || e.srcElement;
      const searchEl = el.closest && el.closest('.select-content');
      if (!searchEl) {
        this.filterTreeShow = false;
      }
    },
    filterTreeFun(val) {
      this.$refs.tree.filter(val);
      this.filterTreeShow = true;
    },
    filterNode(value, data) {
      if (!value) {
        return true;
      }
      return String(data.label).indexOf(value) !== -1;
    },
    regionsClick(data) {
      if (data && objHas(data, 'children')) {
        return;
      }
      this.filterText = data ? data.label : '';
      this.selectVal = data ? data.key : null;
      this.optionChanged(true);
      this._setComponentStatus(false);
      this.componentStatusReadyRun(() => {
        this.emitQuery();
      }, 50);
      this.filterTreeShow = false;
    },

    ...mapMutations(['setComponentStatus', 'deleteComponentStatus']),
    loadWidget(pageStatus) {
      this.setBorderRadius();
      this.pageStatus = pageStatus;
      const isLatest = this.checkUpdate();

      // 对旧下拉框的兼容
      if (!isLatest) {
        this.getSelectContentOptionsOld();
        return;
      }
      this.initDefaultValEventObj();
      this._updateConfigProperty();
      this.updateTitle();
      if (!this.isRealTime) {
        const _pageStatus = getVmPageStatus(this);
        const flag = this.checkUpdateParams(_pageStatus);
        if (!flag) {
          this._getSelectContentOptions();
        }
      }

      this.afterLoadWidget();
    },

    // 检查组件字段
    checkUpdate() {
      const { type } = this.config.config.data;
      let flag = true;
      if (!type) {
        flag = false;
      }
      return flag;
    },

    initDefaultValEventObj() {
      const urlDfEvts = this.getUrlDfValEvents(); // url传参获取默认值事件
      Object.entries(urlDfEvts).map(([key, val]) => {
        let evtParameterKey = null;
        let evtParameterVal = null;
        Object.entries(val).map(([key1, val1]) => {
          evtParameterKey = key1;
          evtParameterVal = val1;
        });
        this.defaultValEventObj = {
          eventKey: key,
          wid: '',
          evtParameterKey,
          evtParameterVal,
        };
      });
    },

    // 更新参数前检查下是否和本组件有关
    checkUpdateParams(obj) {
      let flag = false;
      const { defaultValEvent, defaultValFrom, hasDefaultVal } = this.config.config.data;
      const isIgnored = hasDefaultVal && defaultValFrom === 'event' && defaultValEvent.length;
      for (const key in obj) {
        if (key.indexOf(EMIT_PARAMS_OBJ) > -1) {
          const o = obj[key];
          if (o.eventKey) {
            const ev = this.config.events.find(e => e.key === o.eventKey && e.type === 'in');
            if (ev && !(isIgnored && defaultValEvent.includes(ev.key))) {
              flag = true;
            } else if (ev && isIgnored && defaultValEvent.includes(ev.key)) {
              const { eventKey, componentName: wid, keys, parameters } = o;
              const [evtParameterKey] = keys;
              this.defaultValEventObj = { eventKey, wid, evtParameterKey, evtParameterVal: parameters[evtParameterKey] };
              this.initDefaultVal();
            } else {
            }
            break;
          }
        }
      }

      // 是否存在url传参事件
      if (!flag) {
        const matchEvents = getMatchUrlEvents(this.config.events);
        if (Object.keys(matchEvents).length > 0) {
          flag = true;
        }
      }

      if (flag) {
        this.updateParams(obj);
        this._getSelectContentOptions();
      }
      return flag;
    },

    // 更新部分配置的属性
    _updateConfigProperty() {
      this.updateConfigProperty();

      const { width } = this.config.config.property;
      if (width) {
        this.selectStyle.width = `${width}px`;
      } else {
        this.selectStyle.width = '';
      }
      const { property, data } = this.config.config;
      Object.entries(property).map(([i]) => {
        this[i] = property[i];
      });
      this.hasDefaultVal = data.hasDefaultVal;
      this.defaultVal = data.defaultVal;
      this.defaultValFrom = data.defaultValFrom;
      this.setBoxBackground(this.config.config.property, this.boxStyle);
    },
    optionChanged(byUser = false) {
      // 是否已经加载完全部组件
      if (byUser) {
        this.clearCompHistory(); // 清空历史记录，防止其他联动触发类型组件时还是取历史记录
        // 用户主动下拉选择
        return;
      }
      this.initDefaultVal();
    },
    selectContentOptionsChanged() {
      this._setComponentStatus(false);

      // 公共参数
      const { found, value } = this.getSharedParameterValue(true);
      if (found) {
        const option = this.selectContentOptions.find(o => String(o.key) === String(value));
        if (option) {
          this.selectVal = value;
        } else {
          this.selectVal = '';
        }
        return;
      }

      // 预览态页面
      if (!this.isDesignView) {
        // 改变分辨率
        if (visualAction() === 'pageResize') {
          const history = this.getCompHistory(-1);
          if (history && !isEmpty(history.selectVal)) {
            this.selectVal = history.selectVal;
            return;
          }
        }
      }

      this.optionChanged();
    },
    updateTitle() {
      const { title } = this.config.config.property;
      if (title) {
        this.title = title;
      } else {
        this.title = '';
      }
    },

    // 老的下拉框内容
    getSelectContentOptionsOld() {
      this.selectContentOptions = [];
      nextTick(() => {
        this.selectContentOptions = this.config.config.data.tableData;
      });
    },
    getSelectContentOptions() {
      const { type } = this.config.config.data;
      if (type === 'custom') {
        this.getSelectContentOptionscustom();
      } else {
        this.getSelectContentOptionsdataSource();
      }
    },
    getSelectContentOptionscustom() {
      this.clearable = true;
      this.selectContentOptions = this.config.config.data.customTableData;

      // 重置数据异常状态
      this.resetAbnormalType();
    },

    getSelectContentOptionsdataSource() {
      this.clearable = false;
      let params = this.getParams();
      const { data } = this.config.config;

      // api请求，拿到数据
      if (data.dataSourceType) {
        this.isNoData = false;
        this.isLoading = true;
        const method = `getChartData${data.dataSourceType}`;
        params = this.getCorrectParams(params, data.dataSourceType);
        dataModel[method](params, data)
          .then(result => {
            // 重置数据异常状态
            this.resetAbnormalType();
            this.reportIfFieldsError(this.getParams().propertyMapping, result);
            this.handleResult(result);
          })
          .catch(err => {
            this.handleChartDataError(err);
          })
          .finally(() => {
            this.isLoading = false;
          });
      } else {
        // 如果在用户面，则给提示
        if (this.$route.name === 'userHomePage') {
          this.$message({
            message: this.$demoi18n('view.dataSourceTypeEmpty'),
            type: 'warning',
          });
        }
      }
    },
    handleRealTimeCommunication(realTimeData) {
      if (this.config.config.property.isDebounce && this.isStopRealData) {
        return;
      }

      const result = this.getResult(realTimeData);
      if (this.isNoData || this.autoRefreshIsSameRes(result)) {
        this.isLoading = false;
        return;
      }
      this.handleResult(result);
      this.isLoading = false;
    },
    handleResult(result) {
      this.sendDataToConfig(result);
      const arr = [];
      result &&
        result.length &&
        result.forEach(item => {
          arr.push({
            name: item['name'],
            key: item['key'],
            label: item['label'],
            ...item,
          });
        });
      this.selectContentOptions = arr;
    },
    hasVal() {
      if (Array.isArray(this.selectVal)) {
        if (this.selectVal.length) {
          return true;
        }
      } else if (this.selectVal) {
        return true;
      } else {
      }
      return false;
    },
    initDefaultVal() {
      let value = '';
      let name = '';
      const { type } = this.config.config.data;
      if (type === 'custom') {
        const arr = this.selectContentOptions.filter(n => n.isCheck);
        value = arr.map(n => n.key);
      } else if (this.hasDefaultVal) {
        value = this.defaultVal;
        name = this.defaultVal;
        const options = this.selectContentOptions;
        const from = this.defaultValFrom;
        if (options.length) {
          if (from === 'first') {
            value = options[0].key;
            name = options[0].name;
          } else if (from === 'last') {
            value = options[options.length - 1].key;
            name = options[options.length - 1].name;
          } else if (from === 'event') {
            const { evtParameterKey, evtParameterVal } = this.defaultValEventObj || {};
            value = evtParameterVal;
            name = evtParameterKey;
          } else {
          }
        }
      } else {
      }

      if (this.multiple) {
        if (Array.isArray(value)) {
          this.selectVal = value;
        } else {
          this.selectVal = value ? [value] : [];
          this.filterText = name;
        }
      } else {
        if (Array.isArray(value)) {
          this.selectVal = value[0];
        } else {
          this.selectVal = value;
          this.filterText = name;
        }
      }
    },
    _setComponentStatus(hasAsync) {
      this.setComponentStatus({
        pageId: this.pageId,
        widgetInstanceId: this.widgetInstanceId,
        hasAsync: hasAsync,
      });
    },

    // 执行查询
    emitQuery() {
      const configParameters = this.config.events[0].parameters;
      const parameters = {
        [configParameters[0].key]: this.selectVal,
      };
      const keys = [configParameters[0].key];
      const evtKey = this.orgConfig.events[0].key;

      const outObj = {
        [EMIT_PARAMS_OBJ]: {
          eventKey: this.config.events[0].key,
          type: 'terms',
          isSharedParameter: this.isSharedParameter,
          widgetInstanceId: this.widgetInstanceId,
          keys,
          parameters,
          componentName: 'select',
          sendTime: new Date().getTime(),
        },
      };
      const selectItem = (this.selectContentOptions || []).filter(({ key }) => {
        if (Array.isArray(this.selectVal)) {
          return this.selectVal.includes(key);
        } else {
          return key === this.selectVal;
        }
      });
      const emitParams = this.multiple ? selectItem : selectItem[0] || {};
      this.executeAction('', { selectVal: this.selectVal, orgData: emitParams });
      if (this.widgetInstanceId) {
        this.beforeEmit(outObj);
        this.vsEmit(evtKey, outObj);

        // 发送联动面板的高级事件
        this.sendAdvancedLinkagge(emitParams);
      } else {
        EventBus.$emit(evtKey, outObj);
      }
    },
    setBorderRadius() {
      const borderRadius = this.config.config.property.borderRadius || 4;
      this.$refs.defSelect?.$el?.style?.setProperty('--el-border-radius-base', `${borderRadius}px`);
    },
    setBoxBackground,
    emitBlankMsg() {
      this.selectVal = '';
    },
  },
};
</script>

<style lang="less" scoped>
// 图表通用样式，主要有黑色loading 和 黑色 ‘没有数据’，样式名需一致
@import '../../common/chart.less';
</style>
<style lang="less" scoped>
@bgColor: #0d263a;
@borderColor: #588ba8;
.select-box {
  background-color: var(--vs-bg-color);
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
  position: relative;
  margin: 0 auto;
  padding-top: 1px;
  .select-content {
    width: 100%;
    box-sizing: border-box;
    display: flex;
    align-items: center;
    justify-content: center;
    flex: 0.96;
    &.relativePos {
      position: relative;
    }
    // 标题竖线统一样式
    .sign {
      display: inline-block;
      position: absolute;
      width: 4px;
      height: 16px;
      background-color: #409eff;
      left: 0;
    }
    .mapping-scope {
      display: inline-block;
      color: #f56c6c;
      margin-right: 4px;
      line-height: 1;
    }
    .el-select {
      flex: 1;
    }
    .select-title {
      display: inline-block;
      margin-right: 9px;
      margin-left: 9px;
      font-size: 12px;
      flex-shrink: 0;
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap;
      height: 26px;
      line-height: 26px !important;
      color: var(--vs-color);
    }
    .regions-tree-body {
      width: 100%;
      position: relative;
      .regions-tree-search {
        padding: 10px;
        box-sizing: border-box;
        font-size: 12px;
        :deep(.el-input__inner) {
          height: 28px;
          line-height: 28px;
          padding-right: 30px;
        }
        :deep(.el-input__clear) {
          margin-right: 10px;
        }
      }
      .filter-tree {
        position: absolute;
        min-width: 100%;
        max-height: 270px;
        overflow-y: auto;
        overflow-x: hidden;
        border: 1px solid #dcdfe6;
        z-index: 9999999999;
        padding: 7px;
      }

      :deep(.el-tree > .el-tree-node) {
        display: inline-block;
        width: 100%;

        .el-tree-node__label {
          font-size: 12px;
        }

        &:focus > .el-tree-node__content {
          background-color: transparent;
        }

        .el-tree-node__expand-icon:not(.is-leaf)::before {
          content: ' ';
          background-image: url('../region/images/regions-tree-icon.png');
          background-position: center center;
          background-repeat: no-repeat;
          width: 12px;
          height: 12px;
          display: inline-block;
        }

        .el-tree-node__expand-icon {
          svg {
            display: none;
          }
        }
      }
    }
  }
  .select-box-select {
    line-height: 28px;
    :deep(.el-select__tags) {
      flex-wrap: nowrap;
      overflow: hidden;
    }
    :deep(.el-input__inner) {
      height: 24px !important;
      font-size: 12px;
    }
  }
}
.light {
}
.dark {
  .select-title {
    color: #00f7ff;
  }

  .select-content .regions-tree-body .filter-tree {
    border: 1px solid #588ba8 !important;
    background-color: #0d263a !important;
  }
}
</style>
